--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
sbapp/pyogg/opus_decoder.py 17c4febc96c145692d730ea3728e7a6d6c363e4e (17c4febc) Text, 9.05 KB
Tff7b72import T7ee787ctypes
Tff7b72from T7ee787. Tff7b72import Te6edf3opus
Tff7b72from T7ee787.T7ee787pyogg_error Tff7b72import Te6edf3PyOggError
Tff7b72class T56d364OpusDecoderTb4b4b4:
Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_decoder Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_samples_per_second Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_pcm_buffer Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_pcm_buffer_ptr Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_pcm_buffer_size_int Tff7b72= Tff7b72None
T8b949e# TODO: Check if there is clean up that we need to do when
T8b949e# closing a decoder.
T8b949e#
T8b949e# User visible methods
T8b949e#
Tff7b72def Td2a8ffset_channelsTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3nTb4b4b4)Tb4b4b4:
T8b949e"""Set the number of channels.
n must be either 1 or 2.
The decoder is capable of filling in either mono or
interleaved stereo pcm buffers.
"""
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_decoder Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72if Te6edf3n Tff7b72< T79c0ff0 Tff7b72or Te6edf3n Tff7b72> T79c0ff2Tb4b4b4:
Tff7b72raise Te6edf3PyOggErrorTb4b4b4(
Ta5d6ff"Ta5d6ffInvalid number of channels in call to Ta5d6ff"Tff7b72+
Ta5d6ff"Ta5d6ffset_channels()Ta5d6ff"
Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72= Te6edf3n
Tff7b72elseTb4b4b4:
Tff7b72raise Te6edf3PyOggErrorTb4b4b4(
Ta5d6ff"Ta5d6ffCannot change the number of channels after Ta5d6ff"Tff7b72+
Ta5d6ff"Ta5d6ffthe decoder was created. Perhaps Ta5d6ff"Tff7b72+
Ta5d6ff"Ta5d6ffset_channels() was called after decode()?Ta5d6ff"
Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_create_pcm_bufferTb4b4b4(Tb4b4b4)
Tff7b72def Td2a8ffset_sampling_frequencyTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3samples_per_secondTb4b4b4)Tb4b4b4:
T8b949e"""Set the number of samples (per channel) per second.
samples_per_second must be one of 8000, 12000, 16000,
24000, or 48000.
Internally Opus stores data at 48000 Hz, so that should be
the default value for Fs. However, the decoder can
efficiently decode to buffers at 8, 12, 16, and 24 kHz so
if for some reason the caller cannot use data at the full
sample rate, or knows the compressed data doesn't use the
full frequency range, it can request decoding at a reduced
rate.
"""
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_decoder Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72if Te6edf3samples_per_second Tff7b72in Tb4b4b4[T79c0ff8000Tb4b4b4, T79c0ff12000Tb4b4b4, T79c0ff16000Tb4b4b4, T79c0ff24000Tb4b4b4, T79c0ff48000Tb4b4b4]Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_samples_per_second Tff7b72= Te6edf3samples_per_second
Tff7b72elseTb4b4b4:
Tff7b72raise Te6edf3PyOggErrorTb4b4b4(
Ta5d6ff"Ta5d6ffSpecified sampling frequency Ta5d6ff"Tff7b72+
Ta5d6ff"Ta5d6ff(Tffd700{:d}Ta5d6ff) Ta5d6ff"Tff7b72.Td2a8ffformatTb4b4b4(Te6edf3samples_per_secondTb4b4b4)Tff7b72+
Ta5d6ff"Ta5d6ffwas not one of the accepted valuesTa5d6ff"
Tb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72raise Te6edf3PyOggErrorTb4b4b4(
Ta5d6ff"Ta5d6ffCannot change the sampling frequency after Ta5d6ff"Tff7b72+
Ta5d6ff"Ta5d6ffthe decoder was created. Perhaps Ta5d6ff"Tff7b72+
Ta5d6ff"Ta5d6ffset_sampling_frequency() was called after decode()?Ta5d6ff"
Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_create_pcm_bufferTb4b4b4(Tb4b4b4)
Tff7b72def Td2a8ffdecodeTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3encoded_bytesTb4b4b4: Tffa657memoryviewTb4b4b4)Tb4b4b4:
T8b949e"""Decodes an Opus-encoded packet into PCM.
"""
T8b949e# If we haven't already created a decoder, do so now
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_decoder Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_decoder Tff7b72= Tff7b72selfTff7b72.Td2a8ff_create_decoderTb4b4b4(Tb4b4b4)
T8b949e# Create a ctypes array from the memoryview (without copying
T8b949e# data)
Te6edf3Buffer Tff7b72= Te6edf3ctypesTff7b72.Td2a8ffc_char Tff7b72* Tffa657lenTb4b4b4(Te6edf3encoded_bytesTb4b4b4)
Te6edf3encoded_bytes_ctypes Tff7b72= Te6edf3BufferTff7b72.Td2a8fffrom_bufferTb4b4b4(Te6edf3encoded_bytesTb4b4b4)
T8b949e# Create pointer to encoded bytes
Te6edf3encoded_bytes_ptr Tff7b72= Te6edf3ctypesTff7b72.Td2a8ffcastTb4b4b4(
Te6edf3encoded_bytes_ctypesTb4b4b4,
Te6edf3ctypesTff7b72.Td2a8ffPOINTERTb4b4b4(Te6edf3ctypesTff7b72.Td2a8ffc_ubyteTb4b4b4)
Tb4b4b4)
T8b949e# Store length of encoded bytes into int32
Te6edf3len_int32 Tff7b72= Te6edf3opusTff7b72.Td2a8ffopus_int32Tb4b4b4(
Tffa657lenTb4b4b4(Te6edf3encoded_bytesTb4b4b4)
Tb4b4b4)
T8b949e# Check that we have a PCM buffer
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_pcm_buffer Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72raise Te6edf3PyOggErrorTb4b4b4(Ta5d6ff"Ta5d6ffPCM buffer was not configured.Ta5d6ff"Tb4b4b4)
T8b949e# Decode the encoded frame
Te6edf3result Tff7b72= Te6edf3opusTff7b72.Td2a8ffopus_decodeTb4b4b4(
Tff7b72selfTff7b72.Td2a8ff_decoderTb4b4b4,
Te6edf3encoded_bytes_ptrTb4b4b4,
Te6edf3len_int32Tb4b4b4,
Tff7b72selfTff7b72.Td2a8ff_pcm_buffer_ptrTb4b4b4,
Tff7b72selfTff7b72.Td2a8ff_pcm_buffer_size_intTb4b4b4,
T79c0ff0 T8b949e# TODO: What's Forward Error Correction about?
Tb4b4b4)
T8b949e# Check for any errors
Tff7b72if Te6edf3result Tff7b72< T79c0ff0Tb4b4b4:
Tff7b72raise Te6edf3PyOggErrorTb4b4b4(
Ta5d6ff"Ta5d6ffAn error occurred while decoding an Opus-encoded Ta5d6ff"Tff7b72+
Ta5d6ff"Ta5d6ffpacket: Ta5d6ff"Tff7b72+
Te6edf3opusTff7b72.Td2a8ffopus_strerrorTb4b4b4(Te6edf3resultTb4b4b4)Tff7b72.Td2a8ffdecodeTb4b4b4(Ta5d6ff"Ta5d6ffutfTa5d6ff"Tb4b4b4)
Tb4b4b4)
T8b949e# Extract just the valid data as bytes
Te6edf3end_valid_data Tff7b72= Tb4b4b4(
Te6edf3result
Tff7b72* Te6edf3ctypesTff7b72.Td2a8ffsizeofTb4b4b4(Te6edf3opusTff7b72.Td2a8ffopus_int16Tb4b4b4)
Tff7b72* Tff7b72selfTff7b72.Td2a8ff_channels
Tb4b4b4)
T8b949e# Create memoryview of PCM buffer to avoid copying data during slice.
Te6edf3mv Tff7b72= Tffa657memoryviewTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_pcm_bufferTb4b4b4)
T8b949e# Cast memoryview to chars
Te6edf3mv Tff7b72= Te6edf3mvTff7b72.Td2a8ffcastTb4b4b4(Ta5d6ff'Ta5d6ffcTa5d6ff'Tb4b4b4)
T8b949e# Slice memoryview to extract only valid data
Te6edf3mv Tff7b72= Te6edf3mvTb4b4b4[Tb4b4b4:Te6edf3end_valid_dataTb4b4b4]
Tff7b72return Te6edf3mv
Tff7b72def Td2a8ffdecode_missing_packetTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3frame_durationTb4b4b4)Tb4b4b4:
T8b949e""" Obtain PCM data despite missing a frame.
frame_duration is in milliseconds.
"""
T8b949e# Consider frame duration in units of 0.1ms in order to
T8b949e# avoid floating-point comparisons.
Tff7b72if Tffa657intTb4b4b4(Te6edf3frame_durationTff7b72*T79c0ff10Tb4b4b4) Tff7b72not Tff7b72in Tb4b4b4[T79c0ff25Tb4b4b4, T79c0ff50Tb4b4b4, T79c0ff100Tb4b4b4, T79c0ff200Tb4b4b4, T79c0ff400Tb4b4b4, T79c0ff600Tb4b4b4]Tb4b4b4:
Tff7b72raise Te6edf3PyOggErrorTb4b4b4(
Ta5d6ff"Ta5d6ffFrame duration (Tffd700{:f}Ta5d6ff) is not one of the accepted valuesTa5d6ff"Tff7b72.Td2a8ffformatTb4b4b4(Te6edf3frame_durationTb4b4b4)
Tb4b4b4)
T8b949e# Calculate frame size
Te6edf3frame_size Tff7b72= Tffa657intTb4b4b4(
Te6edf3frame_duration
Tff7b72* Tff7b72selfTff7b72.Td2a8ff_samples_per_second
Tff7b72/Tff7b72/ T79c0ff1000
Tb4b4b4)
T8b949e# Store frame size as int
Te6edf3frame_size_int Tff7b72= Te6edf3ctypesTff7b72.Td2a8ffc_intTb4b4b4(Te6edf3frame_sizeTb4b4b4)
T8b949e# Decode missing packet
Te6edf3result Tff7b72= Te6edf3opusTff7b72.Td2a8ffopus_decodeTb4b4b4(
Tff7b72selfTff7b72.Td2a8ff_decoderTb4b4b4,
Tff7b72NoneTb4b4b4,
T79c0ff0Tb4b4b4,
Tff7b72selfTff7b72.Td2a8ff_pcm_buffer_ptrTb4b4b4,
Te6edf3frame_size_intTb4b4b4,
T79c0ff0 T8b949e# TODO: What is this Forward Error Correction about?
Tb4b4b4)
T8b949e# Check for any errors
Tff7b72if Te6edf3result Tff7b72< T79c0ff0Tb4b4b4:
Tff7b72raise Te6edf3PyOggErrorTb4b4b4(
Ta5d6ff"Ta5d6ffAn error occurred while decoding an Opus-encoded Ta5d6ff"Tff7b72+
Ta5d6ff"Ta5d6ffpacket: Ta5d6ff"Tff7b72+
Te6edf3opusTff7b72.Td2a8ffopus_strerrorTb4b4b4(Te6edf3resultTb4b4b4)Tff7b72.Td2a8ffdecodeTb4b4b4(Ta5d6ff"Ta5d6ffutfTa5d6ff"Tb4b4b4)
Tb4b4b4)
T8b949e# Extract just the valid data as bytes
Te6edf3end_valid_data Tff7b72= Tb4b4b4(
Te6edf3result
Tff7b72* Te6edf3ctypesTff7b72.Td2a8ffsizeofTb4b4b4(Te6edf3opusTff7b72.Td2a8ffopus_int16Tb4b4b4)
Tff7b72* Tff7b72selfTff7b72.Td2a8ff_channels
Tb4b4b4)
Tff7b72return Tffa657bytesTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_pcm_bufferTb4b4b4)Tb4b4b4[Tb4b4b4:Te6edf3end_valid_dataTb4b4b4]
T8b949e#
T8b949e# Internal methods
T8b949e#
Tff7b72def Td2a8ff_create_pcm_bufferTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_samples_per_second Tff7b72is Tff7b72None
Tff7b72or Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72is Tff7b72NoneTb4b4b4)Tb4b4b4:
T8b949e# We cannot define the buffer yet
Tff7b72return
T8b949e# Create buffer to hold 120ms of samples. See "opus_decode()" at
T8b949e# https://opus-codec.org/docs/opus_api-1.3.1/group__opus__decoder.html
Te6edf3max_duration Tff7b72= T79c0ff120 T8b949e# milliseconds
Te6edf3max_samples Tff7b72= Te6edf3max_duration Tff7b72* Tff7b72selfTff7b72.Td2a8ff_samples_per_second Tff7b72/Tff7b72/ T79c0ff1000
Te6edf3PCMBuffer Tff7b72= Te6edf3opusTff7b72.Td2a8ffopus_int16 Tff7b72* Tb4b4b4(Te6edf3max_samples Tff7b72* Tff7b72selfTff7b72.Td2a8ff_channelsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_pcm_buffer Tff7b72= Te6edf3PCMBufferTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_pcm_buffer_ptr Tff7b72= Tb4b4b4(
Te6edf3ctypesTff7b72.Td2a8ffcastTb4b4b4(Te6edf3ctypesTff7b72.Td2a8ffpointerTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_pcm_bufferTb4b4b4)Tb4b4b4,
Te6edf3ctypesTff7b72.Td2a8ffPOINTERTb4b4b4(Te6edf3opusTff7b72.Td2a8ffopus_int16Tb4b4b4)Tb4b4b4)
Tb4b4b4)
T8b949e# Store samples per channel in an int
Tff7b72selfTff7b72.Td2a8ff_pcm_buffer_size_int Tff7b72= Te6edf3ctypesTff7b72.Td2a8ffc_intTb4b4b4(Te6edf3max_samplesTb4b4b4)
Tff7b72def Td2a8ff_create_decoderTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e# To create a decoder, we must first allocate resources for it.
T8b949e# We want Python to be responsible for the memory deallocation,
T8b949e# and thus Python must be responsible for the initial memory
T8b949e# allocation.
T8b949e# Check that the sampling frequency has been defined
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_samples_per_second Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72raise Te6edf3PyOggErrorTb4b4b4(
Ta5d6ff"Ta5d6ffThe sampling frequency was not specified before Ta5d6ff"Tff7b72+
Ta5d6ff"Ta5d6ffattempting to create an Opus decoder. Perhaps Ta5d6ff"Tff7b72+
Ta5d6ff"Ta5d6ffdecode() was called before set_sampling_frequency()?Ta5d6ff"
Tb4b4b4)
T8b949e# The sampling frequency must be passed in as a 32-bit int
Te6edf3samples_per_second Tff7b72= Te6edf3opusTff7b72.Td2a8ffopus_int32Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_samples_per_secondTb4b4b4)
T8b949e# Check that the number of channels has been defined
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72raise Te6edf3PyOggErrorTb4b4b4(
Ta5d6ff"Ta5d6ffThe number of channels were not specified before Ta5d6ff"Tff7b72+
Ta5d6ff"Ta5d6ffattempting to create an Opus decoder. Perhaps Ta5d6ff"Tff7b72+
Ta5d6ff"Ta5d6ffdecode() was called before set_channels()?Ta5d6ff"
Tb4b4b4)
T8b949e# The number of channels must also be passed in as a 32-bit int
Te6edf3channels Tff7b72= Te6edf3opusTff7b72.Td2a8ffopus_int32Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_channelsTb4b4b4)
T8b949e# Obtain the number of bytes of memory required for the decoder
Te6edf3size Tff7b72= Te6edf3opusTff7b72.Td2a8ffopus_decoder_get_sizeTb4b4b4(Te6edf3channelsTb4b4b4)Tb4b4b4;
T8b949e# Allocate the required memory for the decoder
Te6edf3memory Tff7b72= Te6edf3ctypesTff7b72.Td2a8ffcreate_string_bufferTb4b4b4(Te6edf3sizeTb4b4b4)
T8b949e# Cast the newly-allocated memory as a pointer to a decoder. We
T8b949e# could also have used opus.od_p as the pointer type, but writing
T8b949e# it out in full may be clearer.
Te6edf3decoder Tff7b72= Te6edf3ctypesTff7b72.Td2a8ffcastTb4b4b4(Te6edf3memoryTb4b4b4, Te6edf3ctypesTff7b72.Td2a8ffPOINTERTb4b4b4(Te6edf3opusTff7b72.Td2a8ffOpusDecoderTb4b4b4)Tb4b4b4)
T8b949e# Initialise the decoder
Te6edf3error Tff7b72= Te6edf3opusTff7b72.Td2a8ffopus_decoder_initTb4b4b4(
Te6edf3decoderTb4b4b4,
Te6edf3samples_per_secondTb4b4b4,
Te6edf3channels
Tb4b4b4)Tb4b4b4;
T8b949e# Check that there hasn't been an error when initialising the
T8b949e# decoder
Tff7b72if Te6edf3error Tff7b72!= Te6edf3opusTff7b72.Td2a8ffOPUS_OKTb4b4b4:
Tff7b72raise Te6edf3PyOggErrorTb4b4b4(
Ta5d6ff"Ta5d6ffAn error occurred while creating the decoder: Ta5d6ff"Tff7b72+
Te6edf3opusTff7b72.Td2a8ffopus_strerrorTb4b4b4(Te6edf3errorTb4b4b4)Tff7b72.Td2a8ffdecodeTb4b4b4(Ta5d6ff"Ta5d6ffutfTa5d6ff"Tb4b4b4)
Tb4b4b4)
T8b949e# Return our newly-created decoder
Tff7b72return Te6edf3decoder
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────